
package com.feib.ebilling.job;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.feib.ebilling.job.service.BankingFeedbackService;
import com.feib.ebilling.job.service.FtpService;
import com.feib.ebilling.job.util.StringUtils;


/**
 * @title (#)BankingFeedbackBussinessDate.java<br>
 * @description 銀行代收通路銷帳批次回饋，營業日出銷帳檔<br>
 * @author Yaude Huang<br>
 * @version 1.0.0 2011/06/17
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2011/06/17 create by Yaude Huang<br>
 */
@Service("bankingFeedbackBussinessDate")
public class BankingFeedbackBussinessDate {

    public static Logger logger = LoggerFactory.getLogger(BankingFeedbackBussinessDate.class);

    public static final SimpleDateFormat BASIC_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    
    private static ApplicationContext ctx = null;

    @Resource(name="bankingFeedbackService")
    private BankingFeedbackService bankingFeedbackService;

    @Resource(name="ftpService")
    private FtpService ftpService;

    @Resource(name="batchProperties")
    private Properties batchProperties;

    /**
     * 銀行代收通路銷帳批次回饋
     * @param args array, args[0]民國日期<br>
     * 不輸入，抓系統時間處理
     */
    public static void main(String[] args) {

    	BankingFeedbackBussinessDate.ctx = new ClassPathXmlApplicationContext(
                        new String[] {"applicationContext-config.xml", "applicationContext-dao.xml", "applicationContext-properties.xml"});
        boolean bResult = true;
        Date start = new Date();
        logger.info("[開始] 銀行代收通路銷帳批次回饋 - 營業日出銷帳檔 - {}", BASIC_DATE_TIME_FORMAT.format(start));
        try {
        	BankingFeedbackBussinessDate bankingFeedbackBussinessDate = (BankingFeedbackBussinessDate)BankingFeedbackBussinessDate.ctx.getBean("bankingFeedbackBussinessDate");
        	String processDate = "";
        		
            if (args.length==0){
            	/* 傳輸日期 --> 系統日前一日 */
                processDate = StringUtils.GetStrCDateDiff( StringUtils.GetStrCDate() , -1);            	
            }else{ 	
            	if (args.length==1 && args[0].equals("-getFile")){
            		processDate = StringUtils.GetStrCDateDiff( StringUtils.GetStrCDate() , -1);            		
            		/* 從PBHTR取得銷帳資料 */   
            		logger.info("轉換銷帳參數：" + args[0]);  
            		bResult = bankingFeedbackBussinessDate.doConvertPBHTR(processDate);
                    
            	}else if (args.length==1 && !args[0].equals("-getFile")){
            		/* 執行指定日期、時間檔案 */      
                    logger.info("傳入銷帳參數：" + args[0]);  
                    processDate = args[0];
            	}   
            	
                if (args.length==2 && args[1].equals("-getFile")){
                	/* 執行指定日期、時間檔案 */      
                    logger.info("傳入銷帳參數：" + args[0]);  
                    processDate = args[0];
                    /* 從PBHTR取得銷帳資料 */  
                    logger.info("轉換銷帳參數：" + args[1]);  
                    bResult = bankingFeedbackBussinessDate.doConvertPBHTR(processDate);                    
                }   
            }
            logger.info("銷帳日期：" + processDate);
            if (bResult && bankingFeedbackBussinessDate.doFeedBack(processDate)){
                logger.info("銷帳成功：" + processDate);
            }else{
                logger.info("銷帳失敗：" + processDate);
            }
            /* 20111103 車貸客戶依優利指示銷帳 */
            if (bResult && bankingFeedbackBussinessDate.doFeedBack2(StringUtils.ConvCDate2EDate(StringUtils.GetStrCDate()))){
                logger.info("車貸策略聯盟銷帳成功：" + StringUtils.ConvCDate2EDate(StringUtils.GetStrCDate()));
            }else{
                logger.info("車貸策略聯盟銷失敗：" + StringUtils.ConvCDate2EDate(StringUtils.GetStrCDate()));
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        finally{
            Date end = new Date();
            logger.info("[結束] 銀行代收通路銷帳批次回饋 - 營業日出銷帳檔 - {}", BASIC_DATE_TIME_FORMAT.format(end));
            logger.info("共費時 - " + ((end.getTime() - start.getTime()) / 1000) + " 秒");
        }

    }
    public boolean doConvertPBHTR(String sSystemDate){
    	
    	StringBuffer sContent = new StringBuffer();
    	String localFolderProperty = "D:\\ebilling\\temp";
    	String sFileName = "DMPBHTR.cvt";
    	
    	long  ll_total = 0;
    	long  ll_row = 0;
    	
    	try {
	    	File ftpFile = new File(localFolderProperty + "\\" + sFileName);
	        if(ftpFile.exists()){
	            logger.info("Read file : {}", ftpFile.getAbsolutePath());                    
	            BufferedReader in = new BufferedReader(new FileReader(ftpFile));
	            String str = null; 
	            /*
                                               帳號：00200100007743  遠銀受託子龍建設首善  2001
                                               帳號：02200100014217  惠宇文化願景管理委員會  2002
                */
	            while ((str = in.readLine()) != null) {
	            	ll_row ++;
	            	if (ll_row % 1000 ==0) logger.info("Process : {}", ll_row);	            	
                    if  ((str.substring(0, 14).equals("00200100007743") && str.substring(239, 243).equals("2001")) ||
                     	 (str.substring(0, 14).equals("02200100014217") && str.substring(239, 243).equals("2002")) ){
                    	 /* CRDB & 虛擬帳號 */                    	
                    	 if ( str.substring(68, 69).equals("2") && StringUtils.isLong(str.substring(237, 253))){                    		 
                    		 ll_total++;
	                    	 /* 實體帳號 */
	                    	 sContent.append(str.substring(0, 14));
	                    	 /* 交易日 */
	                    	 sContent.append(StringUtils.ConvEDate2CDate(str.substring(28, 36)));
	                    	 /* 交易時間 */
	                    	 sContent.append(str.substring(36, 44));
	                    	 /* 營業日 */
	                    	 sContent.append(StringUtils.ConvEDate2CDate(str.substring(14, 22)));
	                    	 /* 交易種類(自動化為0) */
	                    	 sContent.append(str.substring(50, 51));
	                    	 /* 交易代號(自動化為空白) */
	                    	 sContent.append(str.substring(51, 53));
	                    	 /* 摘要(037為匯款), 自動化為 1 */
	                    	 sContent.append(str.substring(53, 56));
	                    	 /* 交易金額 */
	                    	 sContent.append(str.substring(70, 81));
	                    	 /* 虛擬帳號 */
	                    	 sContent.append(str.substring(237, 253));
	                    	 /* ATM機號 */
	                    	 sContent.append("        ");
	                    	 /* 交易行(891為跨行) */
	                    	 sContent.append(str.substring(42, 45));
	                    	 /* 工作站機號 */
	                    	 sContent.append("00");
	                    	 /* 交易序號 */
	                    	 sContent.append("00000");
	                    	 /* 轉帳銀行 */
	                    	 sContent.append("000");
	                    	 /* 轉帳帳號 */
	                    	 sContent.append("0000000000000000");
	                    	 /* 財金交易代理行 */
	                    	 sContent.append("000");
	                    	 /* 財金交易序號 */
	                    	 sContent.append("0000000");
	                    	 /* 更正記號(0:正常,1:更正) */
	                    	 sContent.append(str.substring(69, 70));
	                    	 /* 通路別(0:臨櫃,1:網銀,2:ATM(或網路ATM),3:中心轉帳BIO),4:自行XML,8:跨行匯款 */
	                    	 sContent.append("0");
	                    	 /* 保留 */
	                    	 sContent.append(StringUtils.PadString("R", " ",59,""));
	                    	 /* E */
	                    	 sContent.append("E"); 
	                    	 sContent.append("\r\n");
                    	 }else{
                    		 logger.info("DR or Wrong virtual account : {}", str); 
                    	 }
                     }
	            }	
	            in.close();
	            File backupFile = new File(localFolderProperty + "\\" + sFileName + "." + sSystemDate);
	            if (ftpFile.renameTo(backupFile)){
	                logger.info("Backup Source to : {}", backupFile.getAbsoluteFile());
	            }else{
	            	logger.error("Backup Source Fail : {}", backupFile.getAbsoluteFile());
	            }
	            /* 筆數檔 */
		    	ftpService.putFTPFile("FEIB", sSystemDate, 
		    			StringUtils.PadString("R", "0", 8, String.valueOf(ll_total) ), "VC_" + sSystemDate + "_CNT.TXT");
		    	
		    	/* 明細檔 */
		    	ftpService.putFTPFile("FEIB", sSystemDate, sContent.toString(), "VC_" + sSystemDate + ".TXT");
	        }else{
	            /* 無下載檔案資料 */        
	            logger.error("[錯誤]Open {} failed.", sFileName);   
	            return false;  
	        }	    	
	        return true;  
    	}
        catch (Exception e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }
    /**
     * 取得檔案並新增至虛擬帳號銷帳日誌
     * @param sSystemDate 日期
     * @param sSystemTime_Begin 時間區間起
     * @param sSystemTime_End 時間區間迄
     * @return 成功(True)或是敗(False)
     */
    public boolean doFeedBack(String sSystemDate){
        try{

            /* 取得資料庫所有「虛擬帳號」對映之「實體帳號」 */
            HashMap<String, Integer> hmAccount = new HashMap<String, Integer>();
            List<Map<String, Object>> rds = bankingFeedbackService.getRealAccounts();
            for(Map<String, Object> rd: rds)
            {
                String sAcctID = ((String)rd.get("ACCOUNT_NO")).trim();
                if (! hmAccount.containsKey(sAcctID)){
                    hmAccount.put(sAcctID, new Integer(1));
                    logger.info("「{}」 虛擬帳號入帳實體帳號：{}", ((String)rd.get("GROUP_NAME")),  sAcctID);
                }
            }

            boolean bRtn = true;
            String cnt = "";
            String localFolderProperty = batchProperties.getProperty("LocalFolder");
          
            /* FTP 取得銷帳筆數檔 */
            String sFileName = "VC_" + sSystemDate + "_CNT.TXT";
                
            if (ftpService.retryGetFtpFile("FEIB", sFileName)){
                /* 檢核檔案是否已產生  */                                
                File ftpFile = new File(localFolderProperty + "\\" + sFileName);
                System.out.println("localFolderProperty file : "+ localFolderProperty + "\\" + sFileName);
                
                if(ftpFile.exists()){
                    logger.info("Read file : {}", ftpFile.getAbsolutePath());                    
                    BufferedReader in = new BufferedReader(new FileReader(ftpFile));
                    String str = null;                                                               
                    while ((str = in.readLine()) != null) {
                        /* 檔案總筆數 */ 
                        cnt = str.substring(0,8).trim();                                      
                    }                        
                }else{
                    /* 無下載檔案資料 */        
                    logger.error("[錯誤]Open {} failed.", sFileName);
                    bRtn = false;
                }
            }else{
                /* FTP 取檔失敗，前一日非營業日取不到檔案 */       
                logger.info("Get Ftp file {} failed", sFileName);
                bRtn = true; 
            }

            /* FTP 取得銷帳明細檔 */
            sFileName = "VC_" + sSystemDate + ".TXT";
            
            // 檢核是否已經有檔名相同且已處理過了
            if (this.bankingFeedbackService.hasWriteoff(sFileName))
            {
                logger.error("[錯誤]檔名 {} 於資料表FEEDBACK_LOG 中已有銷帳成功紀錄.", sFileName);
                bRtn = false; 
            }
            else
            {
                logger.info("刪除銀行代收通路銷帳日誌, 檔名 {}", sFileName);
                this.bankingFeedbackService.removeBankFeedbackLog(sFileName);
            }            

            /* 如果第一個檔案下載失敗，第二個檔案就不下載了。 */
            if (bRtn == true && !"00000000".equals(cnt) &&
                            ftpService.retryGetFtpFile("FEIB", sFileName) ){
                /* 檢核檔案是否已銷帳  */
                File ftpFile = new File(localFolderProperty + "\\" + sFileName);
                if(ftpFile.exists()){
                    logger.info("Read file : {}", ftpFile.getAbsolutePath());
                    BufferedReader in = new BufferedReader(new FileReader(ftpFile));
                    String str = null;                               
                    long  totalcount = 0;
                    long  realcount = 0;
                    while ((str = in.readLine()) != null) {
                        totalcount++;
                        String[] sData = new String[19]; 
                        /* 實體帳號 */                                              
                        sData[0] = str.substring(0,14).trim();                                          
                        if (hmAccount.get(sData[0]) == null){
                            /* 系統無實體帳號要入帳，跳過該筆資料不檢核 */                                              
                            continue;
                        }                                                                       
                        /* 交易日 */
                        sData[1] = str.substring(14,22); // 這裡是民國年
                        sData[1] = String.valueOf(Integer.parseInt(sData[1])+19110000); // 轉為西元年月日
                        /* 交易時間 */
                        sData[2] = str.substring(22,30); // HHMMSShh
                        /* 營業日 */
                        sData[3] = str.substring(30,38); // 這裡是民國年
                        sData[3] = String.valueOf(Integer.parseInt(sData[3])+19110000); // 轉為西元年月日
                        /* 交易種類(自動化為0) */
                        sData[4] = str.substring(38,39);
                        /* 交易代號(自動化為空白) */
                        sData[5] = str.substring(39,41);
                        /* 摘要(037為匯款), 自動化為 1 */
                        sData[6] = str.substring(41,44);
                        /* 交易金額 */
                        sData[7] = str.substring(44,55);
                        /* 虛擬帳號  */
                        sData[8] = str.substring(55,71);
                        if (sData[8].length() == 16 && sData[8].substring(0,2).equals("00")){
                        	/* 虛擬帳號應為14碼  */
                            sData[8] = sData[8].substring(2,16);
                        }else{
                        	sData[8] = sData[8].trim();
                        }                            
                        /* ATM機號  */
                        sData[9] = str.substring(71,79);
                        /* 交易行  (891為跨行)*/
                        sData[10] = str.substring(79,82);
                        /* 工作站代號  */
                        sData[11] = str.substring(82,84);
                        /* 交易序號 */
                        sData[12] = str.substring(84,89);
                        /* 轉帳銀行 */
                        sData[13] = str.substring(89,92);
                        /* 轉帳帳號 */
                        sData[14] = str.substring(92,108);
                        /* 財金交易代理行 */
                        sData[15] = str.substring(108,111);
                        /* 財金交易序號 */
                        sData[16] = str.substring(111,118);
                        /* 沖正記號 (0正常、1沖正) */
                        sData[17] = str.substring(118,119);
                        /* 通路別(0:臨櫃,1:網銀,2:ATM,3:中心轉帳BIO) */
                        sData[18] = str.substring(119,120);
                        
                        /* 新增至銀行繳款通路銷帳日誌 */                            
                        this.bankingFeedbackService.addBankFeedbackLog(sData, sFileName);
                        realcount++;
                    }                                       
                    if (totalcount != Long.parseLong(cnt)){
                        logger.error("[錯誤]虛擬帳號銷帳檔案筆數不合： " + cnt + "，請人工檢核...");
                        /* 刪除已寫入銀行繳款通路銷帳日誌 */                                                  
                        logger.info("Delete FeeBack Data:" + sFileName);
                        this.bankingFeedbackService.removeBankFeedbackLog(sFileName);                            
                        return false;
                    }else{
                        logger.info("虛擬帳號銷帳檔案筆數： {}", cnt);
                        logger.info("實際符合銷帳檔案筆數： {}", StringUtils.PadString("R", "0", 8, String.valueOf(realcount)));
                        
                        doWriteOff(sFileName);
                    }
                }else{                             
                    /* Local 讀檔失敗 */
                    logger.error("[錯誤]Open failed.", sFileName);
                    bRtn = false;
                }
            }else{                                       
                if ("00000000".equals(cnt)){
                    logger.info("無銷帳資料可回饋");
                    bRtn = true;
                }else{
                    /* FTP 取檔失敗 */
                    logger.error("[錯誤]Get Ftp file {} failed.", sFileName);
                    bRtn = false;
                }
            }    
           
            return bRtn;
        }catch (Exception ex){
            logger.error("[錯誤]" + ex.toString(), ex);
            return false;
        }
    }
    
    public boolean doFeedBack2(String sSystemDate){
		try {
			boolean bRtn = true;
			String localFolderProperty = batchProperties.getProperty("LocalFolder");
            
			/* 確認優利會給檔案名稱為系統日期 */
			String sFileName = "TYPAY_" + sSystemDate + ".txt";
			
			/* 取得FTP檔案 */
			if (bRtn == true && ftpService.retryGetFtpFile("FEIB", sFileName)) {
				
				File ftpFile = new File(localFolderProperty + "\\" + sFileName);
				if (ftpFile.exists()) {
					
					logger.info("Read file : {}", ftpFile.getAbsolutePath());					
					String str = null;	
					long cnt = 0;
					long total = 0;
					List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
					FileInputStream fileInputStream = new FileInputStream(ftpFile);
			        BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, "Big5"));    			          			            
			        while ((str = reader.readLine()) !=null ){			        	
			        	if(str.length() > 0){
		                    //處理讀取BOM(byte-order mark)格式檔案,在讀取utf8檔案的開頭會有utf8檔案格式的標記,需略過此標記再重串內容,標記16進位EF BB BF 
		                    int c = str.charAt(0);
		                    if(c == 65279){
		                    	str = str.substring(1, str.length());
		                    }
		                }			        	
						/* 檔案有中文需特殊處理 */
						Map<String, Object> map = new HashMap<String, Object>();
						map.put("sFileName", sFileName);
						/* 銷帳帳號 */
						map.put("USERNO", StringUtils.DBCSsubstring(str, 223, 239));						
						/* 繳款人(合約)編號 */
						map.put("PAYER_ID", StringUtils.DBCSsubstring(str, 103, 119));
						/* 期數 */ 
						map.put("PERIOD", StringUtils.DBCSsubstring(str, 23, 25));
						/* 應繳款日 */
						map.put("PAYMENT_DEADLINE", StringUtils.DBCSsubstring(str, 151, 159));
						/* 實際繳款日 */
						map.put("TX_DATE", StringUtils.DBCSsubstring(str, 197, 205));
						/* 繳費金額(應攤還本金 + 本期利息) */
						map.put("AMOUNT", Integer.parseInt(StringUtils.DBCSsubstring(str, 135, 143)) + 
								          Integer.parseInt(StringUtils.DBCSsubstring(str, 143, 151)) );
						/* 繳款性質(0 ：期付款，2：解約款 ) */
						map.put("PAY_TYPE", StringUtils.DBCSsubstring(str, 221, 222));
						/* 繳款管道 */
						map.put("CHANNEL", StringUtils.DBCSsubstring(str, 222, 223));
						list.add(map);
						/* 加總筆數、金額 */
						cnt++;
						total += Long.parseLong(StringUtils.DBCSsubstring(str, 135, 143)) + Long.parseLong(StringUtils.DBCSsubstring(str, 143, 151));
					}
					logger.info("車貸策略聯盟銷帳檔案筆數： {}", cnt);
					logger.info("車貸策略聯盟銷帳檔案金額： {}", total);
					doWriteOff2(list);
				} else {
					/* Local 讀檔失敗 */
					logger.error("[錯誤]Open failed.", sFileName);
					bRtn = false;
				}
			} else {
				/* FTP 取檔失敗 */
				logger.error("[錯誤]Get Ftp file {} failed.", sFileName);
				bRtn = false;
			}
			return bRtn;
		} catch (Exception ex) {
			logger.error("[錯誤]" + ex.toString(), ex);
			return false;
		}
	}
 
    /* 銷帳程式 */
    public void doWriteOff(String sFileName)
    {        
        try{
            this.bankingFeedbackService.writeoffByFile(sFileName);
            
         }catch (Exception ex){
             logger.error("[錯誤]" + ex.toString(), ex);         
         }
    }
    public void doWriteOff2(List<Map<String, Object>> list)
    {        
        try{
            this.bankingFeedbackService.writeoffByFile2(list);
            
         }catch (Exception ex){
             logger.error("[錯誤]" + ex.toString(), ex);         
         }
    }
}
